using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using XNALibrary.Interfaces;
using XNALibrary.Game;
using XNALibrary.Lighting;

namespace XNALibrary.Entities
{
    public class Entity : IEntity
    {
        private Vector3 position;
        private Vector3 rotation;
        private Model model;
        private float scale;
        private Matrix localWorld;
        private BaseEffect baseEffect;

        #region Properties
        public Matrix LocalWorld
        {
            get { return localWorld; }
            set { localWorld = value; }
        }

        public float Scale
        {
            get { return scale; }
            set { scale = value; }
        }

        public Model Model
        {
            get { return model; }
            set { model = value; }
        }

        public Vector3 Rotation
        {
            get { return rotation; }
            set { rotation = value; }
        }

        public void RotationX(float rotX) { rotation.X = rotX; }
        public void RotationY(float rotY) { rotation.Y = rotY; }
        public void RotationZ(float rotZ) { rotation.Z = rotZ; }

        public Vector3 Position
        {
            get { return position; }
            set { position = value; }
        }
        
        #endregion

        public enum Pass
        {
            Render,
            Depth,
            Normal
        }

        public Entity()
        {
            position = Vector3.Zero;
            RotationX(0);
            RotationY(0);
            RotationZ(0);
            scale = 1.0f;
            localWorld = Matrix.Identity;
            baseEffect = new BaseEffect();
        }

        #region Default models
        public enum Primitives
        {
            Cone,
            Cube,
            Cylinder,
            Sphere,
            Ship,
            Grid,
            Elephant,
            Audi,
            Bunny,
            Teapot,
            SpotLight,
            Light,
            Skullocc,
        }

        #endregion

        #region LoadModels
        public void LoadModel(string path)
        {
            model = BaseGame.content.Load<Model>(path);
            InitModel();
        }

        public void LoadModel(string path, BaseEffect effect)
        {
            model = BaseGame.content.Load<Model>(path);
            this.baseEffect = effect;
            InitModel();
        }

        public void LoadModel(Primitives primitive)
        {
            model = BaseGame.content.Load<Model>("Resources\\Models\\" + primitive.ToString());
            InitModel();
        }

        public void LoadModel(Primitives primitive, BaseEffect effect)
        {
            model = BaseGame.content.Load<Model>("Resources\\Models\\" + primitive.ToString());
            this.baseEffect = effect;
            InitModel();
        }

        private void InitModel()
        {
            baseEffect.ChangeEffectUsedByModel(model);
        }

        #endregion

        #region Draw Methods
        public void Draw()
        {
            //Matrix[] transforms = new Matrix[model.Bones.Count];
            //model.CopyAbsoluteBoneTransformsTo(transforms);

            localWorld = Matrix.CreateRotationY(rotation.Y)
                           * Matrix.CreateRotationX(rotation.X)
                           * Matrix.CreateRotationZ(rotation.Z)
                           * Matrix.CreateTranslation(position)
                           * Matrix.CreateScale(scale);

            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    meshPart.Effect = baseEffect.effectMapping[meshPart];

                foreach (Effect effect in mesh.Effects)
                    baseEffect.UpdateEffectParameters(effect, localWorld);

                mesh.Draw();
            }
        }

        public void Draw(BaseEffect modelEffect)
        {
            localWorld = Matrix.CreateRotationY(rotation.Y)
                           * Matrix.CreateRotationX(rotation.X)
                           * Matrix.CreateRotationZ(rotation.Z)
                           * Matrix.CreateTranslation(position)
                           * Matrix.CreateScale(scale);

            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (ModelMeshPart meshPart in mesh.MeshParts)
                    meshPart.Effect = modelEffect.effect;

                foreach (Effect effect in mesh.Effects)
                    modelEffect.UpdateEffectParameters(effect, localWorld);

                mesh.Draw();
            }
        } 

        #endregion
    }
}